package com.bupt.hotel.hvac.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bupt.hotel.hvac.common.exception.BusinessException;
import com.bupt.hotel.hvac.config.HvacConfig;
import com.bupt.hotel.hvac.mapper.CheckInRecordMapper;
import com.bupt.hotel.hvac.model.domain.ServiceRequest;
import com.bupt.hotel.hvac.model.dto.CheckInDTO;
import com.bupt.hotel.hvac.model.dto.ServiceRequestDTO;
import com.bupt.hotel.hvac.model.entity.CheckInRecord;
import com.bupt.hotel.hvac.model.entity.RoomState;
import com.bupt.hotel.hvac.model.enums.ACMode;
import com.bupt.hotel.hvac.model.enums.RoomStatus;
import com.bupt.hotel.hvac.model.vo.BillVO;
import com.bupt.hotel.hvac.model.vo.CheckInRecordVO;
import com.bupt.hotel.hvac.model.vo.RoomStateVO;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 中央控制器服务
 * 协调调度服务、空调服务和计费服务
 */
@Slf4j
@Service
public class CentralControllerService {

    private final SchedulerService schedulerService;
    private final ACService acService;
    private final BillingService billingService;
    private final CheckInRecordMapper checkInRecordMapper;
    private final HvacConfig config;

    /**
     * 最后一次指令时间（防抖）
     */
    private final Map<String, Long> lastCommandTime = new ConcurrentHashMap<>();

    /**
     * 待处理指令的定时器
     */
    private final Map<String, Timer> pendingCommands = new ConcurrentHashMap<>();

    /**
     * 重启检查定时器
     */
    private final Map<String, Timer> restartCheckTimers = new ConcurrentHashMap<>();

    public CentralControllerService(SchedulerService schedulerService,
            ACService acService,
            BillingService billingService,
            CheckInRecordMapper checkInRecordMapper,
            HvacConfig config) {
        this.schedulerService = schedulerService;
        this.acService = acService;
        this.billingService = billingService;
        this.checkInRecordMapper = checkInRecordMapper;
        this.config = config;
        log.info("中央控制器服务初始化完成");
    }

    /**
     * 初始化回调
     */
    @PostConstruct
    public void init() {
        // 注册调度器回调
        schedulerService.setCallbacks(
                // 房间被移到等待队列
                roomId -> {
                    acService.setWaiting(roomId);
                    log.debug("房间 {} 被移到等待队列", roomId);
                },
                // 房间开始服务
                roomId -> {
                    acService.startServing(roomId);
                    log.debug("房间 {} 开始服务", roomId);
                });

        // 注册AC服务的状态变化回调
        // 监听房间达到目标温度的事件
        log.info("中央控制器回调注册完成");
    }

    /**
     * 办理入住
     */
    @Transactional
    public Map<String, Object> checkIn(CheckInDTO dto) {
        String roomId = dto.getRoomId();

        log.info("开始办理入住 - 房间: {}, 客户: {}, 身份证: {}, 入住天数: {}, 房间类型: {}",
                roomId, dto.getGuestName(), dto.getIdCard(), dto.getStayDays(), dto.getRoomType());

        // 检查房间是否已被占用
        CheckInRecord existing = checkInRecordMapper.selectOne(
                new LambdaQueryWrapper<CheckInRecord>()
                        .eq(CheckInRecord::getRoomId, roomId)
                        .eq(CheckInRecord::getCheckedOut, false));

        if (existing != null) {
            throw new BusinessException(String.format("房间 %s 已被占用，请选择其他房间", roomId));
        }

        // 设置默认空调模式（如果未指定，默认制冷）
        ACMode mode = dto.getMode() != null ? dto.getMode() : ACMode.COOLING;

        // 计算房费相关信息
        Double pricePerNight = dto.getRoomType().getPricePerNight();
        Double totalRoomFee = pricePerNight * dto.getStayDays();
        LocalDateTime expectedCheckoutDate = LocalDateTime.now().plusDays(dto.getStayDays());

        // 创建入住记录
        CheckInRecord record = new CheckInRecord();
        record.setRoomId(roomId);
        record.setGuestName(dto.getGuestName());
        record.setGuestPhone(dto.getGuestPhone());
        record.setIdCard(dto.getIdCard());
        record.setStayDays(dto.getStayDays());
        record.setExpectedCheckoutDate(expectedCheckoutDate);
        record.setRoomType(dto.getRoomType());
        record.setPricePerNight(pricePerNight);
        record.setTotalRoomFee(totalRoomFee);
        record.setDeposit(com.bupt.hotel.hvac.common.Constants.STANDARD_DEPOSIT);
        record.setDepositStatus(com.bupt.hotel.hvac.common.Constants.DEPOSIT_STATUS_PAID);
        record.setCheckInTime(LocalDateTime.now());
        record.setMode(mode);
        record.setCheckedOut(false);
        record.setCreateTime(LocalDateTime.now());
        record.setUpdateTime(LocalDateTime.now());

        checkInRecordMapper.insert(record);

        log.info("入住记录创建成功 - 房间: {}, 总房费: {} 元, 押金: {} 元",
                roomId, totalRoomFee, record.getDeposit());

        // 初始化房间
        RoomState roomState = acService.initRoom(roomId, mode);

        Map<String, Object> result = new HashMap<>();
        result.put("success", true);
        result.put("message", String.format("房间 %s 入住办理成功", roomId));
        result.put("checkInRecord", convertToCheckInRecordVO(record));
        result.put("roomState", convertToRoomStateVO(roomState));

        log.info("房间 {} 办理入住成功，客户: {}, 模式: {}", roomId, dto.getGuestName(), dto.getMode());
        return result;
    }

    /**
     * 办理退房结账
     */
    @Transactional
    public BillVO checkout(String roomId) {
        log.info("开始办理退房 - 房间: {}", roomId);

        // 获取入住记录
        CheckInRecord record = checkInRecordMapper.selectOne(
                new LambdaQueryWrapper<CheckInRecord>()
                        .eq(CheckInRecord::getRoomId, roomId)
                        .eq(CheckInRecord::getCheckedOut, false));

        if (record == null) {
            throw new BusinessException(String.format("房间 %s 没有入住记录，无法结账", roomId));
        }

        // 获取房间状态
        RoomState roomState = acService.getRoomState(roomId);
        if (roomState == null) {
            throw new BusinessException(String.format("房间 %s 状态不存在", roomId));
        }

        // 如果空调还在运行，先关机
        if (roomState.getIsOn()) {
            turnOff(roomId);
        }

        // 生成账单
        BillVO bill = billingService.generateBill(roomState, record.getCheckInTime(), LocalDateTime.now());

        // 退还押金
        if (com.bupt.hotel.hvac.common.Constants.DEPOSIT_STATUS_PAID.equals(record.getDepositStatus())) {
            record.setDepositStatus(com.bupt.hotel.hvac.common.Constants.DEPOSIT_STATUS_REFUNDED);
            log.info("退还押金 - 房间: {}, 押金金额: {} 元", roomId, record.getDeposit());
        }

        // 更新入住记录为已退房
        record.setCheckedOut(true);
        record.setActualCheckoutTime(LocalDateTime.now());
        record.setUpdateTime(LocalDateTime.now());
        checkInRecordMapper.updateById(record);

        // 清理房间
        acService.cleanupRoom(roomId);

        log.info("房间 {} 办理退房成功 - 总房费: {} 元, 空调费: {} 元, 押金已退还: {} 元",
                roomId, record.getTotalRoomFee(), bill.getTotalCost(), record.getDeposit());

        return bill;
    }

    /**
     * 开机
     */
    public RoomStateVO turnOn(String roomId) {
        RoomState room = acService.turnOn(roomId);
        if (room == null) {
            throw new BusinessException(String.format("房间 %s 不存在", roomId));
        }

        // 自动发送温控请求到调度器
        ServiceRequest request = new ServiceRequest();
        request.setRoomId(roomId);
        request.setFanSpeed(room.getFanSpeed());
        request.setTargetTemp(room.getTargetTemp());
        request.setCurrentTemp(room.getCurrentTemp());
        request.setTimestamp(System.currentTimeMillis());

        Map<String, Object> scheduleResult = schedulerService.handleRequest(request);
        log.info("房间 {} 开机并发送温控请求，调度结果: {}", roomId, scheduleResult);

        // 重新获取房间状态（调度器可能已更新状态）
        room = acService.getRoomState(roomId);

        return convertToRoomStateVO(room);
    }

    /**
     * 关机
     */
    public RoomStateVO turnOff(String roomId) {
        // 释放服务对象
        schedulerService.releaseService(roomId);

        // 关机
        RoomState room = acService.turnOff(roomId);
        if (room == null) {
            throw new BusinessException(String.format("房间 %s 不存在", roomId));
        }

        // 停止重启检查
        stopRestartCheck(roomId);

        log.info("房间 {} 关机", roomId);
        return convertToRoomStateVO(room);
    }

    /**
     * 发送温控请求（带防抖）
     */
    public Map<String, Object> sendRequest(String roomId, ServiceRequestDTO dto) {
        long now = System.currentTimeMillis();
        long lastTime = lastCommandTime.getOrDefault(roomId, 0L);
        long timeDiff = now - lastTime;

        // 清除之前的待处理命令
        Timer pendingTimer = pendingCommands.remove(roomId);
        if (pendingTimer != null) {
            pendingTimer.cancel();
        }

        Map<String, Object> result = new HashMap<>();

        // 如果时间间隔小于防抖时间，延迟发送
        if (timeDiff < config.getCommandDebounceTime()) {
            Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    executeRequest(roomId, dto);
                    lastCommandTime.put(roomId, System.currentTimeMillis());
                    pendingCommands.remove(roomId);
                }
            }, config.getCommandDebounceTime() - timeDiff);

            pendingCommands.put(roomId, timer);

            result.put("success", true);
            result.put("message", "请求已延迟发送");
            return result;
        } else {
            // 立即发送
            return executeRequest(roomId, dto);
        }
    }

    /**
     * 执行请求
     */
    private Map<String, Object> executeRequest(String roomId, ServiceRequestDTO dto) {
        RoomState roomState = acService.getRoomState(roomId);
        if (roomState == null || !roomState.getIsOn()) {
            throw new BusinessException(String.format("房间 %s 未开机", roomId));
        }

        // 检查是否只是调温
        boolean isTempChangeOnly = roomState.getFanSpeed() == dto.getFanSpeed() &&
                !roomState.getTargetTemp().equals(dto.getTargetTemp());

        // 更新目标温度
        acService.setTargetTemp(roomId, dto.getTargetTemp());

        Map<String, Object> result = new HashMap<>();
        result.put("success", true);

        // 如果风速改变，需要重新请求调度
        if (roomState.getFanSpeed() != dto.getFanSpeed()) {
            acService.setFanSpeed(roomId, dto.getFanSpeed());

            // 创建服务请求
            ServiceRequest request = new ServiceRequest();
            request.setRoomId(roomId);
            request.setTargetTemp(dto.getTargetTemp());
            request.setFanSpeed(dto.getFanSpeed());
            request.setTimestamp(System.currentTimeMillis());
            request.setCurrentTemp(roomState.getCurrentTemp());

            // 提交到调度器
            Map<String, Object> scheduleResult = schedulerService.handleRequest(request);

            if ((Boolean) scheduleResult.get("granted")) {
                // 开始送风
                acService.startServing(roomId);
                result.put("message", "已获得服务");
            } else if ((Boolean) scheduleResult.get("isWaiting")) {
                // 设置为等待状态
                acService.setWaiting(roomId);
                result.put("message", scheduleResult.get("message"));
            }
        } else if (!isTempChangeOnly && roomState.getStatus() != RoomStatus.SERVING) {
            // 如果不是仅调温，且当前没有在服务中，则请求服务
            ServiceRequest request = new ServiceRequest();
            request.setRoomId(roomId);
            request.setTargetTemp(dto.getTargetTemp());
            request.setFanSpeed(dto.getFanSpeed());
            request.setTimestamp(System.currentTimeMillis());
            request.setCurrentTemp(roomState.getCurrentTemp());

            Map<String, Object> scheduleResult = schedulerService.handleRequest(request);

            if ((Boolean) scheduleResult.get("granted")) {
                acService.startServing(roomId);
                result.put("message", "已获得服务");
            } else if ((Boolean) scheduleResult.get("isWaiting")) {
                acService.setWaiting(roomId);
                result.put("message", scheduleResult.get("message"));
            }
        } else {
            result.put("message", "已更新目标温度");
        }

        return result;
    }

    /**
     * 停止重启检查
     */
    private void stopRestartCheck(String roomId) {
        Timer timer = restartCheckTimers.remove(roomId);
        if (timer != null) {
            timer.cancel();
        }
    }

    /**
     * 获取房间状态
     */
    public RoomStateVO getRoomState(String roomId) {
        RoomState room = acService.getRoomState(roomId);
        if (room == null) {
            throw new BusinessException(String.format("房间 %s 不存在", roomId));
        }
        return convertToRoomStateVO(room);
    }

    /**
     * 获取所有房间状态
     */
    public List<RoomStateVO> getAllRoomStates() {
        return acService.getAllRoomStates().stream()
                .map(this::convertToRoomStateVO)
                .collect(Collectors.toList());
    }

    /**
     * 获取已入住房间列表
     */
    public List<String> getOccupiedRooms() {
        List<CheckInRecord> records = checkInRecordMapper.selectList(
                new LambdaQueryWrapper<CheckInRecord>()
                        .eq(CheckInRecord::getCheckedOut, false));
        return records.stream()
                .map(CheckInRecord::getRoomId)
                .collect(Collectors.toList());
    }

    /**
     * 获取入住记录
     */
    public List<CheckInRecordVO> getCheckInRecords() {
        List<CheckInRecord> records = checkInRecordMapper.selectList(
                new LambdaQueryWrapper<CheckInRecord>()
                        .eq(CheckInRecord::getCheckedOut, false));
        return records.stream()
                .map(this::convertToCheckInRecordVO)
                .collect(Collectors.toList());
    }

    /**
     * 一键关机
     */
    public void turnOffAll() {
        List<RoomState> rooms = acService.getAllRoomStates();
        for (RoomState room : rooms) {
            if (room.getIsOn()) {
                turnOff(room.getRoomId());
            }
        }
        log.info("一键关机完成，共关闭 {} 个房间", rooms.size());
    }

    /**
     * 一键开机
     */
    public void turnOnAll() {
        List<RoomState> rooms = acService.getAllRoomStates();
        for (RoomState room : rooms) {
            if (!room.getIsOn()) {
                turnOn(room.getRoomId());

                // 直接执行请求
                ServiceRequestDTO dto = new ServiceRequestDTO();
                dto.setTargetTemp(room.getTargetTemp());
                dto.setFanSpeed(room.getFanSpeed());

                executeRequest(room.getRoomId(), dto);
                lastCommandTime.put(room.getRoomId(), System.currentTimeMillis());
            }
        }
        log.info("一键开机完成，共开启 {} 个房间", rooms.size());
    }

    /**
     * 清空等待队列
     */
    public void clearWaitingQueue() {
        List<String> clearedRoomIds = schedulerService.clearAllWaiting();

        // 将这些房间设置为待机状态
        for (String roomId : clearedRoomIds) {
            RoomState room = acService.getRoomState(roomId);
            if (room != null && room.getIsOn() && room.getStatus() == RoomStatus.WAITING) {
                acService.setStandby(roomId);
            }
        }

        log.info("清空等待队列完成，共清除 {} 个房间", clearedRoomIds.size());
    }

    /**
     * 转换为RoomStateVO
     */
    private RoomStateVO convertToRoomStateVO(RoomState room) {
        RoomStateVO vo = new RoomStateVO();
        vo.setRoomId(room.getRoomId());
        vo.setIsOn(room.getIsOn());
        vo.setMode(room.getMode());
        vo.setCurrentTemp(room.getCurrentTemp());
        vo.setInitialTemp(room.getInitialTemp());
        vo.setTargetTemp(room.getTargetTemp());
        vo.setFanSpeed(room.getFanSpeed());
        vo.setStatus(room.getStatus());
        vo.setTotalCost(room.getTotalCost());
        vo.setTotalPowerConsumption(room.getTotalPowerConsumption());
        vo.setLastUpdateTime(room.getLastUpdateTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
        vo.setServiceStartTime(room.getServiceStartTime() != null
                ? room.getServiceStartTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()
                : null);
        vo.setDetailRecords(new ArrayList<>()); // 详单记录通过账单查询获取
        return vo;
    }

    /**
     * 转换为CheckInRecordVO
     */
    private CheckInRecordVO convertToCheckInRecordVO(CheckInRecord record) {
        CheckInRecordVO vo = new CheckInRecordVO();
        vo.setRoomId(record.getRoomId());
        vo.setGuestName(record.getGuestName());
        vo.setGuestPhone(record.getGuestPhone());

        // 身份证脱敏处理（保留前6位和后4位）
        if (record.getIdCard() != null && record.getIdCard().length() >= 10) {
            String idCard = record.getIdCard();
            vo.setIdCard(idCard.substring(0, 6) + "********" + idCard.substring(idCard.length() - 4));
        } else {
            vo.setIdCard(record.getIdCard());
        }

        vo.setStayDays(record.getStayDays());

        if (record.getExpectedCheckoutDate() != null) {
            vo.setExpectedCheckoutDate(record.getExpectedCheckoutDate()
                    .atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
        }

        vo.setRoomType(record.getRoomType());
        vo.setPricePerNight(record.getPricePerNight());
        vo.setTotalRoomFee(record.getTotalRoomFee());
        vo.setDeposit(record.getDeposit());
        vo.setDepositStatus(record.getDepositStatus());
        vo.setCheckInTime(record.getCheckInTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
        vo.setMode(record.getMode());
        vo.setCheckedOut(record.getCheckedOut());

        return vo;
    }
}
